package appTool

import (
	"errors"
	"gitee.com/kinwyb/appTools/log"
	"gitee.com/kinwyb/conv"
	"github.com/fsnotify/fsnotify"
	"os"
)

type fileConfigReader struct {
	filePath   string
	fileData   []byte
	cfgMap     map[string]string
	oldcfgMap  map[string]string
	watchRun   bool
	watchValue map[string][]*ConfigWatch
}

// LoadFileConfig 依据文件地址加载配置
func LoadFileConfig(filePath string) (*fileConfigReader, error) {
	if filePath == "" {
		return nil, errors.New("配置文件地址空")
	}
	data, err := os.ReadFile(filePath)
	if err != nil {
		return nil, err
	}
	f := &fileConfigReader{
		filePath: filePath,
		fileData: data,
	}
	err = f.init()
	if err != nil {
		return nil, err
	}
	return f, nil
}

// LoadFileConfigByData 依据文件内容加载配置
func LoadFileConfigByData(fileData []byte) (*fileConfigReader, error) {
	if len(fileData) < 1 {
		return nil, errors.New("配置文件内容空")
	}
	f := &fileConfigReader{
		filePath: "",
		fileData: fileData,
	}
	err := f.init()
	if err != nil {
		return nil, err
	}
	return f, nil
}

func (f *fileConfigReader) init() error {
	newCfg := map[string]string{}
	if len(f.fileData) < 1 {
		return errors.New("配置内容空")
	}
	err := json.Unmarshal(f.fileData, &newCfg)
	if err != nil {
		return err
	}
	f.oldcfgMap = f.cfgMap
	f.cfgMap = newCfg
	return nil
}

func (f *fileConfigReader) ReadString(key string, defaultValue string) string {
	if f.cfgMap == nil {
		_ = f.init()
	}
	if v, ok := f.cfgMap[key]; ok {
		if v != "" {
			return systemParseEnvStringValue(v)
		}
	}
	return systemParseEnvStringValue(defaultValue)
}

func (f *fileConfigReader) ReadInt64(key string, defaultValue int64) int64 {
	val := f.ReadString(key, "")
	return conv.ToInt64Default(val, defaultValue)
}

func (f *fileConfigReader) ReadFloat64(key string, defaultValue float64) float64 {
	val := f.ReadString(key, "")
	return conv.ToFloat64Default(val, defaultValue)
}

func (f *fileConfigReader) ReadBool(key string, defaultValue bool) bool {
	val := f.ReadString(key, "")
	return conv.ToBoolDefault(val, defaultValue)
}

func (f *fileConfigReader) WatchKey(key string) *ConfigWatch {
	watch := &ConfigWatch{
		key: key,
	}
	if f.watchValue == nil {
		f.watchValue = map[string][]*ConfigWatch{}
	}
	f.watchValue[key] = append(f.watchValue[key], watch)
	if !f.watchRun && f.filePath != "" {
		go f.watchFileChange()
	}
	return watch
}

func (f *fileConfigReader) watchFileChange() {
	if f.watchRun {
		return
	}
	f.watchRun = true
	defer func() {
		f.watchRun = false
	}()
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.AppTool.WithError(err).Error("无法监听文件变化")
		return
	}
	defer watcher.Close()
	err = watcher.Add(f.filePath)
	if err != nil {
		log.AppTool.WithError(err).Error("无法监听文件变化")
	}
	for {
		select {
		case event, ok := <-watcher.Events:
			if !ok {
				return
			}
			if event.Op&fsnotify.Write == fsnotify.Write {
				err := f.init()
				if err == nil {
					for k, v := range f.watchValue {
						oldVal := f.oldcfgMap[k]
						newVal := f.cfgMap[k]
						if oldVal != newVal {
							for _, fun := range v {
								fun.setValue(newVal, oldVal)
							}
						}
					}
				}
			}
		case err, ok := <-watcher.Errors:
			if !ok {
				return
			}
			log.AppTool.WithError(err).Error("文件变化监听错误:" + err.Error())
		}
	}
}
